package app.dev.ems.web.wicket.page.admin.user;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.HiddenField;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.Fragment;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import app.dev.ems.data.element.FieldType;
import app.dev.ems.data.model.impl.Field;
import app.dev.ems.data.model.impl.ProfileSettings;
import app.dev.ems.data.model.impl.Settings;
import app.dev.ems.dto.AvailableComponent;
import app.dev.ems.web.element.NavigationStatus;
import app.dev.ems.web.element.PageTitles;
import app.dev.ems.web.wicket.page.admin.BaseAdminPage;
import app.dev.ems.web.wicket.panel.menu.vertical.administration.user.UserAdministrationMenuPanel;

import com.google.code.jqwicket.ui.tiptip.TipTipBehavior;
import com.google.code.jqwicket.ui.tiptip.TipTipOptions;

public class UserProfileSettingsPage extends BaseAdminPage {

	private static final long serialVersionUID = -7283417044536040194L;
	
	private final Logger logger = LoggerFactory.getLogger(getClass());
	private boolean settingsIsNew = false;
	
	public UserProfileSettingsPage() throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
		super(NavigationStatus.USER_ADMINISTRATION, NavigationStatus.USER_ADMINISTRATION, UserAdministrationMenuPanel.class);
		Settings settings = getEMSApplication().getEmsManeger().getSettingsManager().getProfileSettings();
		
		if (settings == null) {			
			settingsIsNew = true;
			settings = getEMSApplication().getEmsManeger().getSettingsManager().createNewProfileSettings();
		}
		add(new UserProfileSettingsForm("userProfileSettingsForm", settings));
	}

	private final class UserProfileSettingsForm extends Form<UserProfileSettingsForm> {

		private static final long serialVersionUID = -9178568660958446218L;

		private Settings settings;
		private Fragment componentDefaultFragment;
		private Fragment gridFragment;
		private DropDownChoice<AvailableComponent> componentChoice;
		private boolean componentFragmentVisible;
		private AvailableComponent selectedComponent;

		public UserProfileSettingsForm(String id, Settings settings) {
			super(id);
			setSettings(settings);
			setModel(new CompoundPropertyModel<UserProfileSettingsPage.UserProfileSettingsForm>(this));
			setOutputMarkupPlaceholderTag(true);
			
			AjaxLink<String> info = new AjaxLink<String>("info") {
				
				private static final long serialVersionUID = 7695482971447722696L;

				@Override
				public void onClick(AjaxRequestTarget target) {
					
				}
			};
			String tooltip = 
							"<div style='padding: 10px'>" +
							"	<div style='text-align: center;'>" +
							"		<label style='color: #FFFFFF; font-size: 14px;'>User Profile Component Configuration</label>" +
							"	</div>" +
							"	<hr/>" +
							"	<div style='padding-left: 10px'>" +
							"		<ul style='list-style-type: circle;'>" +
							"			<li>Textfield: You need to add the Label corresponds to the Textfield. This textfield will be available in the User Profile along with its label.</li>" +
							"			<li>Dropdown</li>" +
							"			<li>Radiobutton</li>" +
							"			<li>Checkbox</li>" +
							"		</ul>" +
							"	</div>" +
							"<div>";
			info.add(new TipTipBehavior(new TipTipOptions().content(tooltip).maxWidth("300px")));
			add(info);
			
			if (renderGrid()) {
				gridFragment = getSettingsGridFragment();
			} else {
				gridFragment = getDefaultFragment("gridRefference");
			}
			
			add(gridFragment);

			componentDefaultFragment = getDefaultFragment("componentRefference");
			add(componentDefaultFragment);
			List<AvailableComponent> availableComponents = getEMSApplication().getEmsService().getComponentHandlerService().getAvailableComponents(getProfileSettings());			
			selectedComponent = availableComponents.get(availableComponents.size() - 1);
			componentChoice = new DropDownChoice<AvailableComponent>("componentChoice", new PropertyModel<AvailableComponent>(this, "selectedComponent"), availableComponents);
			componentChoice.setOutputMarkupPlaceholderTag(true);			
			componentChoice.add(new AjaxFormComponentUpdatingBehavior("onChange"){

				private static final long serialVersionUID = 5930799203832749466L;

				@Override
				protected void onUpdate(AjaxRequestTarget target) {
					AvailableComponent component = (AvailableComponent) componentChoice.getDefaultModelObject();
					if(component.getType().equals(FieldType.TEXT_FIELD)) {
						swapComponentFragment(getTextfieldFragment(true), target);
					} else if(component.getType().equals(FieldType.NONE)) {
						swapComponentFragment(getDefaultFragment("componentRefference"), target);
					}
					target.appendJavaScript("updateSelect('"+ componentChoice.getMarkupId() +"');");
				}		
			});
			
			add(componentChoice);

			add(new AjaxButton("submit"){

				private static final long serialVersionUID = -8649726566814582391L;

				@Override
				protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
					if(settingsIsNew) {
						getEMSApplication().getEmsManeger().getSettingsManager().save(getSettings());
					} else {
						getEMSApplication().getEmsManeger().getSettingsManager().update(getSettings());
					}
					setResponsePage(UserProfileSettingsPage.class);
				}

				@Override
				protected void onError(AjaxRequestTarget target, Form<?> form) {
					
				}				
			});
		}

		public Settings getSettings() {
			return settings;
		}

		public void setSettings(Settings settings) {
			this.settings = settings;
		}
		
		private UserProfileSettingsForm getDefaultObjectModel() {
			return (UserProfileSettingsForm) UserProfileSettingsForm.this.getDefaultModelObject();
		}

		private Settings getSettingsFromModelObject() {
			return getDefaultObjectModel().getSettings();
		}

		private ProfileSettings getProfileSettings() {
			return (ProfileSettings) getSettingsFromModelObject().getSettings();
		}

		private Fragment getDefaultFragment(String refference) {
			Fragment fragment = new Fragment(refference, "defaultFragment", this);
			fragment.setOutputMarkupPlaceholderTag(true);
			return fragment;
		}		
		
		private Fragment getSettingsGridFragment() {						
			return new SettingsGridFragment();
		}
		
		private Fragment getTextfieldFragment(boolean clear) {
			return new TextFieldFragment(clear);
		}		

		private String getTextFieldExpression(boolean clear) {
			ProfileSettings profileSettings = getProfileSettings();
			for (Field field : profileSettings.getFields()) {
				if (field.getFieldType().compareTo(FieldType.TEXT_FIELD) == 0 && !field.isInUse()) {
					if(clear) {
						getEMSApplication().getEmsService().getComponentHandlerService().clearTextFieldValue(field, profileSettings);
					}
					
					return field.getName();
				}
			}
			return null;
		}		

		private boolean renderGrid() {
			for (Field field : getProfileSettings().getFields()) {
				if (field.isInUse()) {
					return true;
				}
			}
			return false;
		}		
		
		private void swapComponentFragment(Fragment fragment, AjaxRequestTarget target) {			
			componentDefaultFragment.replaceWith(fragment);
			componentDefaultFragment = fragment;
			target.add(componentDefaultFragment);
		}
		
		private void swapGridFragment(Fragment fragment, AjaxRequestTarget target) {
			gridFragment.replaceWith(fragment);
			gridFragment = fragment;
			target.add(gridFragment);
		}
		
		private void updateComponentChoice(AjaxRequestTarget target) {
			List<AvailableComponent> availableComponents = getEMSApplication().getEmsService().getComponentHandlerService().getAvailableComponents(getProfileSettings());			
			selectedComponent = availableComponents.get(availableComponents.size() - 1);
			componentChoice.setChoices(availableComponents);
			target.add(componentChoice);							
			target.appendJavaScript("updateSelect('"+ componentChoice.getMarkupId() +"');");
		}
		
		private class SettingsGridFragment extends Fragment {
	
			private static final long serialVersionUID = -6127483539019853629L;

			public SettingsGridFragment() {
				super("gridRefference", "settingsGridFragment", UserProfileSettingsForm.this);
				initComponents();
			}
			
			private void initComponents() {
				setOutputMarkupPlaceholderTag(true);				
				
				ListView<Field> settingsGrid = new ListView<Field>("settingsGrid", getProfileSettings().getFields()) {

					private static final long serialVersionUID = 7545335141029513994L;

					@Override
					protected void populateItem(final ListItem<Field> item) {
						final Field field = item.getModelObject();
						if (field.getFieldType().compareTo(FieldType.TEXT_FIELD) == 0 && field.isInUse()) {
							TextFieldGridFragment textFieldGridFragment = new TextFieldGridFragment(field);
							item.add(textFieldGridFragment);
							
							item.add(new AjaxLink<String>("up") {

								private static final long serialVersionUID = 1421312365294227704L;

								@Override
								public void onClick(AjaxRequestTarget target) {
									if(componentFragmentVisible) {
										return;
									}
									
									Collections.swap(getList(), item.getIndex(), item.getIndex() == 0 ? getList().size() - 1 : item.getIndex() - 1);
									target.add(SettingsGridFragment.this);
								}								
							}.add(new TipTipBehavior(new TipTipOptions().content("Up"))));													
							
							item.add(new AjaxLink<String>("down") {

								private static final long serialVersionUID = 7958078243014543002L;

								@Override
								public void onClick(AjaxRequestTarget target) {
									if(componentFragmentVisible) {
										return;
									}
									Collections.swap(getList(), item.getIndex(), item.getIndex() == getList().size() - 1 ? 0 : item.getIndex() + 1);
									target.add(SettingsGridFragment.this);
								}								
							}.add(new TipTipBehavior(new TipTipOptions().content("Down"))));							
							
							item.setVisible(textFieldGridFragment.getValue() != null);						
						} else {
							item.add(new Label("label", "")).add(new Label("value", "")).setVisible(false);
						}
					}
				};

				add(settingsGrid);
			}
			
			private class TextFieldGridFragment extends Fragment {
	
				private static final long serialVersionUID = -1112660212667061232L;
				
				private Field field;
				private String value;
				
				public TextFieldGridFragment(Field field) {			
					super("valueRefference", "textfieldGridFragment", UserProfileSettingsForm.this);
					this.field = field;
					initComponents();
				}
				
				private void initComponents() {
					add(new Label("label", "Textfield"));
					value = getEMSApplication().getEmsService().getComponentHandlerService().getTextFieldLabel(field, getProfileSettings());
					add(new Label("value", value));
					add(new AjaxLink<String>("delete") {
										
						private static final long serialVersionUID = 6714656781106139038L;

						@Override
						public void onClick(AjaxRequestTarget target) {
							if(componentFragmentVisible) {
								return;
							}
							field.setInUse(false);
							getEMSApplication().getEmsService().getComponentHandlerService().clearTextFieldValue(field, getProfileSettings());
							if(renderGrid()) {
								target.add(SettingsGridFragment.this);
							} else {
								swapGridFragment(getDefaultFragment("gridRefference"), target);								
							}	
							updateComponentChoice(target);							
							target.appendJavaScript("$j('#tiptip_holder').hide();");
						}
					}.add(new TipTipBehavior(new TipTipOptions().content("Delete"))));
					
					add(new AjaxLink<String>("edit"){

						private static final long serialVersionUID = 6682130110368412882L;

						@Override
						public void onClick(AjaxRequestTarget target) {
							if(componentFragmentVisible) {
								return;
							}
							field.setInUse(false);
							swapComponentFragment(getTextfieldFragment(false), target);
							target.add(SettingsGridFragment.this);
						}								
					}.add(new TipTipBehavior(new TipTipOptions().content("Edit"))));
				}
				
				public String getValue() {
					return value;
				}
			
			}
		}
		
		private class TextFieldFragment extends Fragment {
			
			private static final long serialVersionUID = -7736586793053487700L;
			
			private boolean clear;
			
			public TextFieldFragment(boolean clear) {
				super("componentRefference", "textfieldFragment", UserProfileSettingsForm.this);
				this.clear = clear;
				componentFragmentVisible = true;
				initComponents();
			}
			
			private void initComponents() {
				setOutputMarkupPlaceholderTag(true);
				TextField<String> inputField = new TextField<String>("inputField", new PropertyModel<String>(getProfileSettings(), getTextFieldExpression(clear)));
				final HiddenField<String> hiddenField = new HiddenField<String>("hiddenField", new Model<String>(getTextFieldExpression(clear)));
				add(hiddenField);
				add(inputField);
				add(new AjaxButton("save", UserProfileSettingsForm.this) {

					private static final long serialVersionUID = 2416788614210821669L;

					@Override
					protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
						UserProfileSettingsForm settingsForm = (UserProfileSettingsForm) UserProfileSettingsForm.this.getDefaultModelObject();
						ProfileSettings profileSettings = (ProfileSettings) settingsForm.getSettings().getSettings();
						for (Field field : profileSettings.getFields()) {
							if (field.getFieldType().compareTo(FieldType.TEXT_FIELD) == 0) {							
								if (field.getName().equals(hiddenField.getValue())) {
									field.setInUse(true);
									break;
								}
							}
						}
						componentFragmentVisible = false;
						if(renderGrid()) {
							swapGridFragment(getSettingsGridFragment(), target);						
						}
						
						swapComponentFragment(getDefaultFragment("componentRefference"), target);			
						updateComponentChoice(target);
					}

					@Override
					protected void onError(AjaxRequestTarget target, Form<?> form) {

					}
				});
			}
		}		
	}	

	@Override
	public String getTitle() {
		return PageTitles.PROFILE_SETTINGS.getTitle();
	}		
}
